﻿using DAL;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace Modbus_PRO
{
    ////枚举类型
    //public enum DataFormat
    //{
    //    ABCD,
    //    BADC,
    //    CDAB,
    //    DCBA
    //}

    public enum StoreArea
    {
        输出线圈0x,
        输入状态1x,
        输出寄存器4x,
        输入寄存器3x
    }

    public enum VarType
    {
        Bit,
        Short,
        UShort,
        Int,
        UInt,
        Float
    }

    public partial class FrmModbusRtu : Form
    {
        public FrmModbusRtu()
        {
            InitializeComponent();
            this.Load += FrmModbusRtu_Load;
        }

        //创建通信对象
        private ModbusRtu objmodbusRtu = new ModbusRtu();

        //系统当前时间
        private string CurrentTime
        {
            get { return DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"); }
        }

        //创建连接标志位
        private bool IsConnected = false;

        #region Load初始化

        private void FrmModbusRtu_Load(object sender, EventArgs e)
        {
            //初始化控件
            lstv_RWmessage.Columns[1].Width = lstv_RWmessage.ClientSize.Width - lstv_RWmessage.Columns[0].Width;

            //端口号
            string[] PortList = SerialPort.GetPortNames();

            if (PortList.Length > 0)
            {
                this.cb_Port.Items.AddRange(PortList);
                this.cb_Port.SelectedIndex = 0;
            }

            //波特率
            this.cb_BaudRate.DataSource = new string[] { "2400", "4800", "9600", "19200", "38400" };
            this.cb_BaudRate.SelectedIndex = 2;

            //校验位
            this.cb_CheckSit.DataSource = Enum.GetNames(typeof(Parity));

            //停止位
            this.cb_StopSit.DataSource = Enum.GetNames(typeof(StopBits));
            this.cb_StopSit.SelectedIndex = 1;

            //数据格式
            this.cb_dataStyle.DataSource = Enum.GetNames(typeof(DataFormat));

            //存储区
            this.cb_SaveSit.DataSource = Enum.GetNames(typeof(StoreArea));

            //数据类型
            this.cb_VarityNumberStyle.DataSource = Enum.GetNames(typeof(VarType));
        }

        #endregion Load初始化

        #region 建立和断开连接

        private void btn_CreateLink_Click(object sender, EventArgs e)
        {
            //判断是否连接
            if (IsConnected)
            {
                Addlog(1, "ModbusRTU已连接，请勿重复连接!");
                return;
            }
            try
            {
                objmodbusRtu.OpenMyCom(int.Parse(this.cb_BaudRate.Text.Trim()), this.cb_Port.Text.Trim(), int.Parse(this.txt_datasit.Text.Trim()), (Parity)Enum.Parse(typeof(Parity), this.cb_CheckSit.SelectedItem.ToString(), false), (StopBits)Enum.Parse(typeof(StopBits), this.cb_StopSit.SelectedItem.ToString(), false));
            }
            catch (Exception ex)
            {
                IsConnected = false;
                Addlog(1, "ModbusRTU连接失败：" + ex.Message);
                return;
            }
            IsConnected = true;
            Addlog(0, "ModbusRTU连接成功!");
        }

        private void btn_breakLink_Click(object sender, EventArgs e)
        {
            objmodbusRtu.CloseMyCom();
            IsConnected = false;
            Addlog(0, "ModbusRTU断开连接");
        }

        #endregion 建立和断开连接

        #region 通用读取方法

        private void btn_Read_Click(object sender, EventArgs e)
        {
            if (!IsConnected)
            {
                Addlog(1, "请先检查与Modbus从站之间的连接");
                return;
            }
            ushort DevAdd = 0;
            ushort Address = 0;
            ushort Length = 0;
            if (!ushort.TryParse(this.txt_SlaveAdd.Text.Trim(), out DevAdd))
            {
                Addlog(1, "读取失败，从站地址必须为正整数");
                return;
            }
            if (!ushort.TryParse(this.txt_Variable.Text.Trim(), out Address))
            {
                Addlog(1, "读取失败，起始地址必须为正整数");
                return;
            }
            if (!ushort.TryParse(this.txt_Length.Text.Trim(), out Length))
            {
                Addlog(1, "读取失败，读取长度必须为正整数");
                return;
            }

            //获取选择的变量类型
            VarType varType = (VarType)Enum.Parse(typeof(VarType), this.cb_VarityNumberStyle.SelectedItem.ToString(), false);
            //获取选择的存储区
            StoreArea storeArea = (StoreArea)Enum.Parse(typeof(StoreArea), this.cb_SaveSit.SelectedItem.ToString(), false);

            //创建字节数组
            byte[] result = null;
            //数据读取
            switch (varType)
            {
                case VarType.Bit:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                            result = objmodbusRtu.ReadOutputStatus(DevAdd, Address, Length);
                            break;

                        case StoreArea.输入状态1x:
                            result = objmodbusRtu.ReadInputStatus(DevAdd, Address, Length);

                            break;

                        case StoreArea.输出寄存器4x:
                        case StoreArea.输入寄存器3x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            return;
                    }
                    string binarystring = string.Empty;
                    if (result != null)
                    {
                        foreach (var item in result)
                        {
                            char[] c = Convert.ToString(item, 2).PadLeft(8, '0').ToCharArray();
                            Array.Reverse(c);
                            binarystring += new string(c);
                        }
                        Addlog(0, "读取成功，结果为:" + binarystring.Substring(0, Length));
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                case VarType.Short:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                        case StoreArea.输入状态1x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            break;

                        case StoreArea.输出寄存器4x:
                            result = objmodbusRtu.ReadKeepReg(DevAdd, Address, Length);
                            break;

                        case StoreArea.输入寄存器3x:
                            break;

                        default:
                            break;
                    }
                    string shortString = string.Empty;
                    if (result != null && result.Length == Length * 2)
                    {
                        for (int i = 0; i < result.Length; i += 2)
                        {
                            shortString += BitConverter.ToInt16(Get16ByteArray(result, i, objmodbusRtu.DataFormat), 0).ToString() + "";
                        }
                        Addlog(0, "读取成功，结果为:" + shortString.Trim());
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                case VarType.UShort:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                        case StoreArea.输入状态1x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            break;

                        case StoreArea.输出寄存器4x:
                            result = objmodbusRtu.ReadKeepReg(DevAdd, Address, Length);
                            break;

                        case StoreArea.输入寄存器3x:
                            break;

                        default:
                            break;
                    }
                    string UshortString = string.Empty;
                    if (result != null && result.Length == Length * 2)
                    {
                        for (int i = 0; i < result.Length; i += 2)
                        {
                            UshortString += BitConverter.ToUInt16(Get16ByteArray(result, i, objmodbusRtu.DataFormat), 0).ToString() + "";
                        }
                        Addlog(0, "读取成功，结果为:" + UshortString.Trim());
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                case VarType.Int:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                        case StoreArea.输入状态1x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            break;

                        case StoreArea.输出寄存器4x:
                            result = objmodbusRtu.ReadKeepReg(DevAdd, Address, Length * 2);
                            break;

                        case StoreArea.输入寄存器3x:
                            result = objmodbusRtu.ReadInputReg(DevAdd, Address, Length * 2);
                            break;

                        default:
                            break;
                    }
                    string intString = string.Empty;
                    if (result != null && result.Length == Length * 4)
                    {
                        for (int i = 0; i < result.Length; i += 4)
                        {
                            intString += BitConverter.ToInt32(Get32ByteArray(result, i, objmodbusRtu.DataFormat), 0).ToString() + "";
                        }
                        Addlog(0, "读取成功，结果为:" + intString.Trim());
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                case VarType.UInt:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                        case StoreArea.输入状态1x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            break;

                        case StoreArea.输出寄存器4x:
                            result = objmodbusRtu.ReadKeepReg(DevAdd, Address, Length * 2);
                            break;

                        case StoreArea.输入寄存器3x:
                            result = objmodbusRtu.ReadInputReg(DevAdd, Address, Length * 2);
                            break;

                        default:
                            break;
                    }
                    string UintString = string.Empty;
                    if (result != null && result.Length == Length * 4)
                    {
                        for (int i = 0; i < result.Length; i += 4)
                        {
                            UintString += BitConverter.ToUInt32(Get32ByteArray(result, i, objmodbusRtu.DataFormat), 0).ToString() + "";
                        }
                        Addlog(0, "读取成功，结果为:" + UintString.Trim());
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                case VarType.Float:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                        case StoreArea.输入状态1x:
                            Addlog(1, "读取失败,存储区类型不正确!");
                            break;

                        case StoreArea.输出寄存器4x:
                            result = objmodbusRtu.ReadKeepReg(DevAdd, Address, Length * 2);
                            break;

                        case StoreArea.输入寄存器3x:
                            result = objmodbusRtu.ReadInputReg(DevAdd, Address, Length * 2);
                            break;

                        default:
                            break;
                    }
                    string floatString = string.Empty;
                    if (result != null && result.Length == Length * 4)
                    {
                        for (int i = 0; i < result.Length; i += 4)
                        {
                            floatString += BitConverter.ToSingle(Get32ByteArray(result, i, objmodbusRtu.DataFormat), 0).ToString() + "";
                        }
                        Addlog(0, "读取成功，结果为:" + floatString.Trim());
                    }
                    else
                    {
                        Addlog(1, "读取失败,请检查地址、类型、或者连接状态");
                    }
                    break;

                default:
                    break;
            }
        }

        #endregion 通用读取方法

        private void btn_Write_Click(object sender, EventArgs e)
        {
            if (!IsConnected)
            {
                Addlog(1, "请先检查与Modbus从站之间的连接");
                return;
            }
            ushort DevAdd = 0;
            ushort Address = 0;
            ushort Length = 0;
            if (!ushort.TryParse(this.txt_SlaveAdd.Text.Trim(), out DevAdd))
            {
                Addlog(1, "写入失败，从站地址必须为正整数");
                return;
            }
            if (!ushort.TryParse(this.txt_Variable.Text.Trim(), out Address))
            {
                Addlog(1, "写入失败，起始地址必须为正整数");
                return;
            }
            if (!ushort.TryParse(this.txt_Length.Text.Trim(), out Length))
            {
                Addlog(1, "写入失败，读取长度必须为正整数");
                return;
            }

            //获取选择的变量类型
            VarType varType = (VarType)Enum.Parse(typeof(VarType), this.cb_VarityNumberStyle.SelectedItem.ToString(), false);
            //获取选择的存储区
            StoreArea storeArea = (StoreArea)Enum.Parse(typeof(StoreArea), this.cb_SaveSit.SelectedItem.ToString(), false);

            bool result = false;
            string SetText = this.txt_WriteNumber.Text.Trim();

            switch (varType)
            {
                case VarType.Bit:
                    switch (storeArea)
                    {
                        case StoreArea.输出线圈0x:
                            bool[] res = GetBoolArray(SetText);
                            result = objmodbusRtu.ForceMultiCoil(DevAdd, Address, res);
                            break;

                        case StoreArea.输入状态1x:
                        case StoreArea.输出寄存器4x:
                        case StoreArea.输入寄存器3x:
                            Addlog(1, "写入失败，类型不支持");
                            break;
                    }
                    Addlog(result ? 0 : 1, result ? "写入成功,写入数值为" + SetText : "写入失败!");
                    break;

                case VarType.Short:
                    break;

                case VarType.UShort:
                    break;

                case VarType.Int:
                    break;

                case VarType.UInt:
                    break;

                case VarType.Float:
                    break;

                default:
                    break;
            }
            //objmodbusRtu.ForceCoil(1,0,true);
        }

        #region 写入日志的通用方法

        /// <summary>
        /// 写入日志的通用方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="info"></param>
        private void Addlog(int type, string info)
        {
            ListViewItem lst = new ListViewItem("" + CurrentTime, type);
            lst.SubItems.Add(info);
            lstv_RWmessage.Items.Add(lst);
        }

        #endregion 写入日志的通用方法

        #region 各种类型的数组截取

        private byte[] Get16ByteArray(byte[] byteArray, int start, DataFormat type)
        {
            byte[] Res = new byte[2];
            if (byteArray != null && byteArray.Length >= start + 2)
            {
                byte[] ResTemp = new byte[2];
                for (int i = 0; i < 2; i++)
                {
                    ResTemp[i] = byteArray[start + i];
                }
                switch (type)
                {
                    case DataFormat.ABCD:
                    case DataFormat.CDAB:
                        Res[0] = ResTemp[1];
                        Res[1] = ResTemp[0];
                        break;

                    case DataFormat.BADC:
                    case DataFormat.DCBA:
                        Res = ResTemp;
                        break;
                }
                return Res;
            }
            else
            {
                return null;
            }
        }

        private byte[] Get32ByteArray(byte[] byteArray, int start, DataFormat type)
        {
            byte[] Res = new byte[2];
            if (byteArray != null && byteArray.Length >= start + 2)
            {
                byte[] ResTemp = new byte[2];
                for (int i = 0; i < 2; i++)
                {
                    ResTemp[i] = byteArray[start + i];
                }
                switch (type)
                {
                    case DataFormat.ABCD:
                        Res[0] = ResTemp[3];
                        Res[1] = ResTemp[2];
                        Res[2] = ResTemp[1];
                        Res[3] = ResTemp[0];
                        break;

                    case DataFormat.CDAB:
                        Res[0] = ResTemp[3];
                        Res[1] = ResTemp[2];
                        Res[2] = ResTemp[1];
                        Res[3] = ResTemp[0];
                        break;

                    case DataFormat.BADC:
                        Res[0] = ResTemp[3];
                        Res[1] = ResTemp[2];
                        Res[2] = ResTemp[1];
                        Res[3] = ResTemp[0];
                        break;

                    case DataFormat.DCBA:
                        Res = ResTemp;
                        break;
                }
                return Res;
            }
            else
            {
                return null;
            }
        }

        #endregion 各种类型的数组截取

        #region 字符串转换布尔数组

        private bool[] GetBoolArray(string val)
        {
            List<bool> Result = new List<bool>();
            if (val.Contains(' '))
            {
                string[] str = Regex.Split(val, "\\s+", RegexOptions.IgnoreCase);
                foreach (var item in str)
                {
                    Result.Add(item.ToLower() == "true" || item.ToLower() == "1");
                }
            }
            else
            {
                Result.Add(val.ToLower() == "true" || val.ToLower() == "1");
            }
            return Result.ToArray();
        }

        #endregion 字符串转换布尔数组

        private void cb_dataStyle_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (objmodbusRtu != null)
            {
                objmodbusRtu.DataFormat = (DataFormat)Enum.Parse(typeof(DataFormat), this.cb_dataStyle.SelectedItem.ToString(), false);
            }
        }
    }
}